/**
 * Created by Wang on 2018/7/4.
 */
class NodeTreeView{
    constructor(){
        this.g = null;
        this.selectedNode = undefined;
        this.fromEdge = undefined;
        this.collapsed = [];
    }

    iterate(rootId,nodeId) {
        if(rootId===nodeId){
            this.collapsed.push(nodeId);
            return true;
        }
        let edges = [...this.g.edges].filter(edge => (!edge.$removed) && edge.from === rootId);
        for (let i = 0; i < edges.length; i++) {
            let found = false;

            if (edges[i].to === nodeId) {
                found = true;
            } else {
                found = this.iterate(edges[i].to,nodeId);
            }

            if (found === true) {
                this.collapsed.push(edges[i].to);
                return true;
            }
        }
        return false;
    }

    collapseTo(node){
        this.iterate(this.g.getRoot(),node);
    }

    collapseAll(){
        this.collapsed=[];
        [...this.g.nodes.values()].forEach(node=>this.collapsed.push(node.id));
    }

    getRoot(){
        let root = this.g.getRoot();
        return root;
    }

    getLinks(id){
        // console.log('GetLinks of '+id);
        let node = this.g.getNode(id);
        let edges = (node==null)?[]:node.getLinks(this.g).sort((edge1,edge2)=>{
            let targetNode1 = this.g.getNode(edge1.to);
            let targetNode2 = this.g.getNode(edge2.to);

            return MyNode.compare(targetNode1,targetNode2);
        });
        // console.log('GetLinks of '+id);
        // console.log(edges);
        return edges;
    }
}

const treeview2 = angular.module('ui.bootstrap.treeview2',[]);
treeview2.directive('treeView', ['$compile', '$templateCache', function ($compile, $templateCache) {
    return {
        restrict: 'E',
        scope: {},
        bindToController: {
            treeService: '='
        },
        controller: function () {
            const that = this;

            this.isCollapsed = function(nodeId) {
                return that.treeService.collapsed.indexOf(nodeId) > -1;
            };

            // toggle when icon clicked
            this.toggleNode = function (node) {
                if(node==null) return;
                let links = node.getLinks(this.treeService.g);
                // collapse / expand
                if (links && links.length > 0) {
                    // add the node to our collapsed array
                    let index = that.treeService.collapsed.indexOf(node.id);

                    if (index === -1)
                        that.treeService.collapsed.push(node.id);
                    else
                        that.treeService.collapsed.splice(index, 1);
                }
            };

            // select when name clicked
            this.selectNode = function (e, node, fromEdge) {
                that.treeService.fromEdge = fromEdge;
                that.treeService.selectedNode = node;

                e.stopPropagation();
                e.preventDefault();
            };

            this.hasChildren = function(node){
                let links = (node==null)?[]: node.getLinks(this.treeService.g);
                return links && links.length >0;
            };

            this.sortByEdgeId = function (edge) {
                return edge.id;
            };
        },
        controllerAs: 'ctrl',
        link: function (scope, element, attrs, ctrl) {
            let isRoot = (!attrs.treeRoot ? true : false);

            let itemInclude = attrs.itemNgInclude || '';
            let nodeRef = attrs.nodeRef;
            let itemIncludeHtml = '';

            if (itemInclude && itemInclude.length > 0) {
                itemIncludeHtml = $templateCache.get(attrs.itemNgInclude);
            }

            element.removeAttr('item-ng-include');
            element.removeAttr('tree-root');

            // template
            let template = '';

            if(isRoot){
                template =  '<ul ng-init="node=ctrl.treeService.getRoot()" >' +
                    '<li drag-accept-node tree-service="ctrl.treeService" node-ref="{{node.id}}">' +
                        '<div ng-click="ctrl.selectNode($event, node, null)" class="node" ng-class="{\'selected\' : node == ctrl.treeService.selectedNode}">' +
                            '<div ng-class="[node.$type]">' +
                            '<i ng-click="ctrl.toggleNode(node)" ng-show="ctrl.hasChildren(node)" ng-class="!ctrl.isCollapsed(node.id) ? \'has-child\' : \'has-child-open\'"></i>' +
                            '<i ng-click="ctrl.toggleNode(node)" class="no-child" ng-show="!ctrl.hasChildren(node)"></i>' +
                            '<span ng-bind="node.getTextWithId()" ng-class="{\'selected\' : node == ctrl.treeService.selectedNode,\'faultMatched\' : node.isMatched,\'faultUnKnown\' : node.unknown}"></span>' +
                            '</div>' +
                        itemIncludeHtml +
                        '</div>' +
                        '<div class="tree-context" ng-class=" \'tree-node-\'+ node.id"><tree-view uib-collapse="!ctrl.isCollapsed(node.id)" tree-service="ctrl.treeService" node-ref="{{node.id}}" tree-root="false" item-ng-include="' + itemInclude + '" ng-class="[node.$type]"></tree-view></div>' +
                    '</li>' +
                    '</ul>';
            }else {
                template =  '<ul >' +
                    '<li  ng-repeat="edge in ctrl.treeService.getLinks(\''+nodeRef+'\') track by edge.id " ng-if="!edge.$removed" ng-init="node=ctrl.treeService.g.getNode(edge.to)" ng-class="{\'fault-is-subgraph\':(node.$is_sub_graph || node.$is_sub_graph2 )}" >' +
                    '<div drag-accept-node tree-service="ctrl.treeService" node-ref="{{node.id}}" ng-click="ctrl.selectNode($event, node, edge.id)" class="node" ng-class="{\'selected\' : node == ctrl.treeService.selectedNode}">' +
                    '<div drag-tree-node node-ref="{{node.id}}"  ng-class="[node.$type]">' +
                    '<i ng-click="ctrl.toggleNode(node)" ng-show="ctrl.hasChildren(node)" ng-class="!ctrl.isCollapsed(node.id) ? \'has-child\' : \'has-child-open\'"></i>' +
                    '<i ng-click="ctrl.toggleNode(node)" class="no-child" ng-show="!ctrl.hasChildren(node)"></i>' +
                    '<span ng-bind="node.getTextWithId()" node-ref="{{node.id}}" ng-class="{\'selected\' : node == ctrl.treeService.selectedNode,\'faultFreedom\':node.$freedom,\'faultMatched\' : node.isMatched,\'faultUnKnown\' : node.unknown}"></span>' +
                    '</div>' +
                    itemIncludeHtml +
                    '</div>' +
                    '<div class="tree-context" ng-class=" \'tree-node-\'+ node.id"><tree-view uib-collapse="!ctrl.isCollapsed(node.id)" tree-service="ctrl.treeService" node-ref="{{node.id}}" tree-root="false" item-ng-include="' + itemInclude + '" ng-class="[node.$type]"></tree-view></div>' +
                    '</li>' +
                    '</ul>';
            }


            if (!isRoot) {
                template = template.replace('[REPLACENODES]', '$parent.node.children');
            } else {
                template = template.replace('[REPLACENODES]', 'ctrl.treeService.getRoot()');
            }

            let compiledHtml = $compile(template)(scope);

            element.append(compiledHtml);
        }
    };
}]);

treeview2.directive('dragTreeNode',['$compile', '$templateCache', function ($compile, $templateCache) {
    return {
        restrict: 'A',
        scope: {},
        bindToController: {
            treeService: '='
        },
        controller: function () {
            const that = this;
        },
        controllerAs: 'ctrl',
        link: function (scope, element, attrs, ctrl) {
            let nodeRef = attrs.nodeRef;
            element.attr('draggable',true);
            element.on("dragstart",function(e) {
                e.originalEvent.dataTransfer.setData("Text", nodeRef);
            });
        }
    };
}]);

treeview2.directive('dragAcceptNode',['$compile', '$templateCache', function ($compile, $templateCache) {
    return {
        restrict: 'A',
        scope: {},
        bindToController: {
            treeService: '='
        },
        controller: function () {
            const that = this;
        },
        controllerAs: 'ctrl',
        link: function (scope, element, attrs, ctrl) {
            let nodeRef = attrs.nodeRef;

            element.on("dragover",function(e) {
                e.preventDefault();
            });
            element.on("drop",function(e) {
                e.preventDefault();
                e.stopPropagation();
                let sourceNode = ctrl.treeService.g.getNode(e.originalEvent.dataTransfer.getData("Text"));
                let targetNode = ctrl.treeService.g.getNode(nodeRef);
                console.info({
                    from:e.originalEvent.dataTransfer.getData("Text"),
                    to:nodeRef,
                    e:e,
                    source:sourceNode.getText(),
                    target:targetNode.getText()
                });

                let dropPair = targetNode.$type + '->' + sourceNode.$type;
                if(dropEnableList.indexOf(dropPair)>=0){
                    // let newNode = jQuery.extend(true,sourceNode,{
                    //     $state:'new',
                    //     id:MyNode.idGenerator++
                    // });
                    // ctrl.treeService.g.addNode(newNode);
                    // ctrl.treeService.g.addLink(targetNode.id,newNode.id);
                    ctrl.treeService.g.addLink(targetNode.id,sourceNode.id);
                    alert("复制链接成功！");
                }
            });
        }
    };
}]);

const dropEnableList=['Fault->Feature','Fault->Reason','Fault->FeatureGroup','Fault->ReasonGroup',
'Feature->Component','Feature->ComponentGroup','Reason->Component','Reason->ReasonGroup',
'FeatureGroup->Feature','FeatureGroup->FeatureGroup','ReasonGroup->Reason','ReasonGroup->ReasonGroup',
'ComponentGroup->Component'];




